package com.sushuo.api.dao;


import java.io.Serializable;
import java.math.BigInteger;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.Query;

import org.hibernate.SQLQuery;
import org.hibernate.transform.Transformers;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.JpaEntityInformationSupport;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.data.repository.NoRepositoryBean;

import com.sushuo.base.bean.sql.Sort;
import com.sushuo.base.bean.sql.PageData;

/**
 * Created by bolinlee on 2017/5/31
 */
@NoRepositoryBean
public class BaseDaoImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID>
implements BaseDao<T, ID> {
    private final EntityManager entityManager;
//    private static final Logger logger = LoggerFactory.getLogger(BaseDaoImpl.class);

    public BaseDaoImpl(Class<T> domainClass, EntityManager em) {
        this(JpaEntityInformationSupport.getEntityInformation(domainClass, em), em);
    }

    public BaseDaoImpl(final JpaEntityInformation<T, ?> entityInformation, final EntityManager entityManager) {
        super(entityInformation, entityManager);
        this.entityManager = entityManager;
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<Map<String, Object>> findListMapBySql(String sql, List<Object> param) {
        Query query = entityManager.createNativeQuery(sql);
        query.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        setParam(param, query);
        return query.getResultList();
    }

    @SuppressWarnings("unchecked")
    @Override
    public <R> List<R> findBeanBySql(String sql, List<Object> param, Class<R> classes) {
        Query query = entityManager.createNativeQuery(sql, classes);
        setParam(param, query);
        return query.getResultList();
    }

    private void setParam(List<Object> param, Query query) {
        if (null != param) {
            int i = 0;
            for (Object o : param) {
                query.setParameter(i+1, o);
            }
        }
    }

    @Override
    public int count(String sql, Map<Integer, Object> params) {
        String countSql = "SELECT count(1) num FROM (" + sql + ") z";
        Query query = entityManager.createNativeQuery(countSql);
        setParam(params, query);
        return Integer.valueOf(String.valueOf(query.getSingleResult()));
    }

    /**
     * 
     * @Title: setParam 
     * @param  params key为参数顺序，从1开始
     * @author zhangzijie
     * @updateTime 2017年8月18日 下午5:03:00
     */
    private void setParam(Map<Integer, Object> params, Query query) {
        if (null != params && params.size() > 0) {
            params.entrySet().stream().forEach(p -> {
                if(p.getKey() > 0) {
                    query.setParameter(p.getKey(), p.getValue());
                }
            });
        }
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<Map<String, Object>> findMapBySqlHasParamOrder(String sql, Map<Integer, Object> params) {
        Query query = entityManager.createNativeQuery(sql);
        query.unwrap(SQLQuery.class).setResultTransformer(
                Transformers.ALIAS_TO_ENTITY_MAP);
        setParam(params, query);
        return query.getResultList();
    }

    @Override
    public PageData<T> findPageBySql(String sql, List<Object> param, Class<T> classes, PageData<T> pageData, Sort sort) {
        Query query = null;
        if (null == pageData) {
            pageData = new PageData<>();
        }
        //计算总记录数
        String countSql = "select count(1) from ("+sql+") z";
        query = entityManager.createNativeQuery(countSql);
        setParam(param, query);
        int totalRecord =((BigInteger) query.getSingleResult()).intValue();
        pageData.setTotalRecord(totalRecord);
        pageData.setTotalPage();
        if(sort!=null){
            sql+=sort.toString();
        }
        if (classes != null) {
            query = entityManager.createNativeQuery(sql, classes);
        } else {
            query = entityManager.createNativeQuery(sql);
            query.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        }
        setParam(param, query);
        query.setFirstResult(pageData.getStartRecord());
        query.setMaxResults(pageData.getPageSize());
        
        @SuppressWarnings("unchecked")
        List<T> result = query.getResultList();
        pageData.setData(result);
        return pageData;
    }
}
